/*
Copyright (C) 2003-2004 Douglas Thain and the University of Wisconsin
Copyright (C) 2005- The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/

#include "domain_name_cache.h"
#include "hash_cache.h"
#include "debug.h"

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/utsname.h>

/* cache domain names for up to five minutes */
#define DOMAIN_NAME_CACHE_LIFETIME 300

static struct hash_cache *name_to_addr=0;
static struct hash_cache *addr_to_name=0;

static int domain_name_cache_init()
{
	if(!name_to_addr) {
		name_to_addr = hash_cache_create(127,hash_string,free);
		if(!name_to_addr) {
			return 0;
		}
	}

	if(!addr_to_name) {
		addr_to_name = hash_cache_create(127,hash_string,free);
		if(!addr_to_name) {
			return 0;
		}
	}

	return 1;
}

int domain_name_cache_canonical( const char *name_or_addr, char *cname )
{
	char addr[DOMAIN_NAME_MAX];
	return domain_name_cache_lookup(name_or_addr,addr) &&
	domain_name_cache_lookup_reverse(addr,cname);
}

int domain_name_cache_lookup( const char *name, char *addr )
{
	char *found, *copy;
	int success;

	if(!domain_name_cache_init()) return 0;

	found = hash_cache_lookup(name_to_addr,name);
	if(found) {
		strcpy(addr,found);
		return 1;
	}

	success = domain_name_lookup(name,addr);
	if(!success) return 0;

	copy = strdup(addr);
	if(!copy) return 1;

	success = hash_cache_insert(name_to_addr,name,copy,DOMAIN_NAME_CACHE_LIFETIME);

	return 1;
}

int domain_name_cache_lookup_reverse( const char *addr, char *name )
{
	char *found, *copy;
	int success;

	if(!domain_name_cache_init()) return 0;

	found = hash_cache_lookup(addr_to_name,addr);
	if(found) {
		strcpy(name,found);
		return 1;
	}

	success = domain_name_lookup_reverse(addr,name);
	if(!success) return 0;

	copy = strdup(name);
	if(!copy) return 1;

	success = hash_cache_insert(addr_to_name,addr,copy,DOMAIN_NAME_CACHE_LIFETIME);

	return 1;
}

static int guess_dns_domain( char *domain )
{
	char line[DOMAIN_NAME_MAX];
	FILE *file;

	file = fopen("/etc/resolv.conf","r");
	if(!file) return 0;

	while(fgets(line,sizeof(line),file)) {
		if(sscanf(line,"search %[^ \t\n]",domain)==1) {
			fclose(file);
			return 1;
		}
		if(sscanf(line,"domain %[^ \t\n]",domain)==1) {
			fclose(file);
			return 1;
		}
	}

	fclose(file);
	return 0;	
}

int domain_name_cache_guess( char *name )
{
	struct utsname n;
	char addr[DOMAIN_NAME_MAX];
	char domain[DOMAIN_NAME_MAX];

	if(uname(&n)<0) return 0;

	if(!domain_name_cache_lookup(n.nodename,addr)) return 0;
	if(!domain_name_cache_lookup_reverse(addr,name)) return 0;

	debug(D_DNS,"finding my hostname: uname = %s, address = %s, hostname = %s",n.nodename,addr,name);

	if(!strncmp(name,"localhost",9) || !strcmp(addr,"127.0.0.1") ) {
		debug(D_DNS,"local address of '%s' (%s) is not very useful.",name,addr);
		if(guess_dns_domain(domain)) {
			sprintf(name,"%s.%s",n.nodename,domain);
			debug(D_DNS,"but /etc/resolv.conf says domain = %s so hostname = %s",domain,name);
			if (!domain_name_cache_lookup(name,addr)) {
				debug(D_DNS,"unfortunately %s is meaningless, so going back to %s",name,n.nodename);
				sprintf(name,"%s",n.nodename);
			}
		} else {
			strcpy(name,n.nodename);
			debug(D_DNS,"cannot find any more info, so use hostname = %s",n.nodename);
		}
	}

	return 1;
}

static char shortname[DOMAIN_NAME_MAX];
static int got_shortname = 0;

int domain_name_cache_guess_short( char *name )
{
	struct utsname n;

	if(got_shortname) {
		strcpy(name,shortname);
		return 1;
	}

	if(uname(&n)<0) return 0;

	strcpy(shortname,n.nodename);

	char *p = strchr(shortname,'.');
	if(p) *p = 0;

	strcpy(name,shortname);
	got_shortname = 1;

	return 1;
}
